package com.xhga.server;

import com.xhga.common.RpcDecoder;
import com.xhga.common.RpcEncoder;
import com.xhga.common.RpcRequest;
import com.xhga.common.RpcResponse;
import com.xhga.register.RpcRegister;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;

import java.util.HashMap;
import java.util.Map;

/**
 * Created by Hua wb on 2018/11/29.
 */
public class RpcServer implements ApplicationContextAware,InitializingBean{

    private RpcRegister rpcRegister;

    private String serverAddress;

    private Map<String, Object> annotationMap = new HashMap();

    public RpcServer(RpcRegister rpcRegister, String serverAddress) {
        this.rpcRegister = rpcRegister;
        this.serverAddress = serverAddress;
        this.rpcRegister.createNode(serverAddress);
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        NioEventLoopGroup bossGroup = new NioEventLoopGroup();
        NioEventLoopGroup workerGroup = new NioEventLoopGroup();
        try {
            ServerBootstrap server = new ServerBootstrap();
            server.group(bossGroup, workerGroup)
                    .channel(NioServerSocketChannel.class)
                    .childHandler(new ChannelInitializer<SocketChannel>(){
                        @Override
                        protected void initChannel(SocketChannel ch) throws Exception {
                            ch.pipeline()
                                    .addLast(new RpcEncoder(RpcResponse.class))
                                    .addLast(new RpcDecoder(RpcRequest.class))
                                    .addLast(new RpcHandler(annotationMap));
                        }
                    })
                    .option(ChannelOption.SO_BACKLOG, 128)
                    .childOption(ChannelOption.SO_KEEPALIVE, true);
            String[] split = serverAddress.split(":");
            ChannelFuture future = server.bind(split[0], Integer.parseInt(split[1])).sync();
            future.channel().closeFuture().sync();
        } catch (Exception e) {
            System.out.println("server netty error...");
        } finally {
            bossGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();
        }
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        Map<String, Object> map = applicationContext.getBeansWithAnnotation(RpcService.class);
        if (map != null) {
            for (Object o:map.values()){
                String name = o.getClass().getAnnotation(RpcService.class).value().getName();
                annotationMap.put(name, o);
            }
        }
    }
}
